package cn.bugstack.config;

import cn.bugstack.types.annotations.DCCValue;
import cn.bugstack.types.common.Constants;
import jodd.util.StringUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.bcel.classfile.Constant;
import org.redisson.api.RBucket;
import org.redisson.api.RTopic;
import org.redisson.api.RedissonClient;
import org.redisson.api.listener.MessageListener;
import org.springframework.aop.framework.AopProxyUtils;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@Configuration
@Data
public class DCCValueBeanFactory implements BeanPostProcessor {


    private static final String BASE_CONFIG_PATH ="group_buy_market_dcc_";

    private final RedissonClient redissonClient;

    private final Map<String,Object> dccObjectMap = new HashMap<>();




    @Bean("dccTopic")
    public RTopic dccRedisTopicListener(RedissonClient redissonClient){
        RTopic topic = redissonClient.getTopic("group_buy_market_dcc");
        topic.addListener(String.class, new MessageListener<String>() {
            @Override
            public void onMessage(CharSequence charSequence, String message) {
                String[] split = message.split(Constants.SPLIT);
                String attribute =  split[0] ;
                String key = BASE_CONFIG_PATH + attribute;
                String value = split[1];
                RBucket<Object> bucket = redissonClient.getBucket(key);
                boolean exists = bucket.isExists();
                if (!exists){
                    return;
                }
                bucket.set(value);
                Object target = dccObjectMap.get(key);
                if (null == target){
                    return;
                }
                Class<?> objBeanClass = target.getClass();

                if (AopUtils.isAopProxy(objBeanClass)){
                    objBeanClass = AopUtils.getTargetClass(objBeanClass);
                }

                try {
                    Field field = objBeanClass.getDeclaredField(attribute);
                    field.setAccessible(true);
                    field.set(objBeanClass,value);
                    field.setAccessible(false);
                }catch (Exception e){
                    log.error("dcc redis topic listener error",e);
                }
            }
        });
        return topic;
    }



    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {

        //判断是否是代理类 代理类获取不到属性信息
        Class<?> targetClass = bean.getClass();
        Object targetBeanObject = bean;
        if (AopUtils.isAopProxy(bean)){
            targetClass = AopUtils.getTargetClass(bean);
            targetBeanObject = AopProxyUtils.getSingletonTarget(bean);
        }
        Field[] declaredFields = targetClass.getDeclaredFields();

        for (Field field : declaredFields) {
            if (!field.isAnnotationPresent(DCCValue.class)){
                continue;
            }
            DCCValue dccValue = field.getAnnotation(DCCValue.class);
            String value = dccValue.value();
            if (StringUtil.isBlank(value)){
                throw new RuntimeException("注解@DCCValue中value is null");
            }
            String[] split = value.split(":");
            String key = BASE_CONFIG_PATH.concat(split[0]);

            String defaultValue = split.length == 2 ? split[1] : null;
            if (StringUtil.isBlank(defaultValue)){
                throw new RuntimeException("注解@DCCValue中value is null");
            }
            String setValue = defaultValue;

            RBucket<String> bucket = redissonClient.getBucket(key);
            boolean exists = bucket.isExists();
            if (!exists){
                bucket.set(defaultValue);
            }else {
                setValue = bucket.get();
            }

            //使属性变成可以访问
            field.setAccessible(true);
            try {
                field.set(targetBeanObject,setValue);
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            }
            field.setAccessible(false);

            dccObjectMap.put(key,targetBeanObject);
        }

        return bean;
    }
}
